const utils = require("../utils");
const { reservedWordsMap, globalIdentMap, globalStringsMap, onEventMap } = require("./zjsdata");
const zjs_ast = require("./zjs_ast");
const { transformUsingTS } = require("./transformer");

const acorn = require("acorn");
const bParser = require("@babel/parser");
const generator = require("@babel/generator");
// const walk = require("acorn-walk");
// const babel = require("@babel/core");
// const prettier = require("prettier");

function zjsTranspile(jsFile, zjsFileContent) {
  const jsFileContent = transpile(zjsFileContent);
  utils.writeFileContents(jsFile, jsFileContent);
}

function transpile(source) {
  let tokenlist = [];
  let prevLineNo = 1;
  
  function commentHandler(isBlock, text, start, end, startLoc, endLoc) {
    if (startLoc.line !== prevLineNo) {
      tokenlist.push('\n'.repeat(startLoc.line - prevLineNo)); 
    }
    if (isBlock) {
      tokenlist.push("/*" + text + "*/");
    } else {
      tokenlist.push("//" + text); // 不使用行信息的话, 须在末尾加一个 \n
    }
    prevLineNo = endLoc.line;
    // console.log('comment', prevLineNo);
  }
  
  function tokenHandler(token) {
    // console.log(token);
    if (token.loc.start.line !== prevLineNo) {
      tokenlist.push('\n'.repeat(token.loc.start.line - prevLineNo));
    }
    // https://github.com/acornjs/acorn/blob/master/acorn/src/tokentype.js
    switch (token.type.label) {
      case 'name':
      //#region keyword type
      case 'break':
      case 'case':
      case 'catch':
      case 'continue':
      case 'debugger':
      case 'default':
      case 'do':
      case 'else':
      case 'finally':
      case 'for':
      case 'function':
      case 'if':
      case 'return':
      case 'switch':
      case 'throw':
      case 'try':
      case 'var':
      case 'const':
      case 'while':
      case 'with':
      case 'new':
      case 'this':
      case 'super':
      case 'class':
      case 'extends':
      case 'export':
      case 'import':
      case 'null':
      case 'true':
      case 'false':
      case 'in':
      case 'instanceof':
      case 'typeof':
      case 'void':
      case 'delete':
      //#endregion
        // console.log(token);
        /* if (token.value) {
          if (Object.keys(reservedWordsMap).includes(token.value)) {
            token.value = reservedWordsMap[token.value]; // 已在 acorn.js 中转换
          }
        } */
        if (token.value.match(/[\u4e00-\u9fa5]/) && token.value in globalIdentMap) { // hasOwnProperty in globalIdentMap
          // console.log(token.value, typeof token.value);
          token.value = globalIdentMap[token.value];
        } else
        if (token.value.slice(-1) === "时"  && token.value in onEventMap) {
          token.value = onEventMap[token.value];
        }
        tokenlist.push((typeof token.value === "string"? token.value : token.value.name) + " ");
        break;
      
      case '[':
      //#region punc type
      case ']':
      case '{':
      case '}':
      case '(':
      case ')':
      case ',':
      case ';':
      case ':':
      case '.':
      case '?':
      case '?.':
      case '=>':
      case '...':
      case '`':
      case '${':
      case '=':
      case '_=':
      case '++/--':
      case '!/~':
      case '||':
      case '&&':
      case '|':
      case '^':
      case '&':
      case '==/!=/===/!==':
      case '</>/<=/>=':
      case '<</>>/>>>':
      case '+/-':
      case '%':
      case '*':
      case '/':
      case '**':
      case '??':
      //#endregion
        tokenlist.push(token.value ? token.value : token.type.label);
          break; 

      case 'num':
      case 'template':
        tokenlist.push(token.value);
        break;
      
      case 'regexp':
        tokenlist.push(token.value.value);
        break;
      
      case 'string':
        if (token.value) {
          /* if (Object.keys(globalStringsMap).includes(token.value)) { // 2021-7-16 已解决
            token.value = globalStringsMap[token.value]; // typeof tag 转换, 尚未找到其提示在哪里提供
          } else { */
          if (token.value.match(/[\u4e00-\u9fa5]/)) {
            if (token.value === '使用严格模式') {
              token.value = 'use strict';
              tokenlist.push("'" + token.value + "'");
              break;
            } else {
              r =  token.value.match(/\[EN(.+)NE\]/);
              if (r) {
                token.value = r[1]; // 时区名称: '长[ENlongNE]' -> timeZoneName: "long"
                tokenlist.push("'" + token.value + "'");
                break;
              }
            }
          }
          // 嵌套单/双引号问题, 转义符问题? 使用 JSON.stringify() ?
          token.value = "'" + token.value.replace(/\\/g, "\\\\").
                                          replace(/\n/g, "\\n").          
                                          replace(/\r/g, "\\r").
                                          replace(/\t/g, "\\t").
                                          replace(/\0/g, "\\0").
                                          // replace(/\b/g, "\\b").
                                          replace(/\f/g, "\\f").
                                          replace(/\v/g, "\\v").
                                          replace(/'/g, "\\'") + "'";
        } else 
        if (token.value === '') {
          token.value = "''";
        }
        tokenlist.push(token.value);
        break;
      
      case 'privateId':
        tokenlist.push('#' + token.value + ' ');
        break;

      // case 'invalidTemplate': ??

      default: // punc type going here? 'eof' and else what?
        // console.log(token);
        tokenlist.push(token.value ? token.value + ' ': token.type.label);
        break;
    }
    prevLineNo = token.loc.end.line;
    // console.log('token', prevLineNo);
  }

  try {
    let tokens = acorn.tokenizer(source, { ecmaVersion: "latest", onComment: commentHandler, onToken: tokenHandler, locations: true });
    // console.log(tokens);
    for (let token of tokens) {} // 这个空循环不能少, 否则结果为空, 异步原因吗?
    // setTimeout(function() {console.log(tokenlist)}, 2000);
    // console.log(tokenlist);
    // const result = babel.transformSync(tokenlist.slice(1).join(' '));
    // console.log(result);
    // return result.code;
    // return prettier.format(tokenlist.slice(1).join(" "), { parser: "babel" });
    let eCode = tokenlist.slice(1).join('');  // 第一个 token 是 eof?
    // console.log(eCode);
    eCode = transformUsingTS(eCode); // 可能有类型注释, 所以需要先于 babel 处理
    // console.log(eCode);
    /* let ast = bParser.parse(eCode, {sourceType: "unambiguous"});
    zjs_ast.astHandler(ast);
    
    let options = {
      // auxiliaryCommentBefore: "下面的代码系由极速中文 Web 开发语言转译而成",
      // concise: true,
      retainLines: true
    }
    const output = new generator.CodeGenerator(
      ast, options, eCode
    ).generate();
    // console.log(output); */
    // return /* output.code; */ transformUsingTS(output.code); // 在 类型() 等转换后所得信息的支持下, 再次 transform 以翻译剩余标识符? 
    return transformUsingTS(eCode, true);
  } catch (error) {
    console.log(error);
  }
}

module.exports = {
  zjsTranspile,
  transpile
};
